home *** CD-ROM | disk | FTP | other *** search
- /*
- * SFskyedit - Star Fighter 3000 sky colours editor
- * Back-end functions
- * Copyright (C) 2001 Chris Bazley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public Licence as published by
- * the Free Software Foundation; either version 2 of the Licence, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public Licence for more details.
- *
- * You should have received a copy of the GNU General Public Licence
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /* ANSI library files */
- #include <stdbool.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
-
- /* RISC OS library files */
- #include "kernel.h"
- #include "flex.h"
-
- /* My library files */
- #include "err.h"
- #include "msgtrans.h"
- #include "Macros.h"
- #include "SFformats.h"
-
- /* Local headers */
- #include "Utils.h"
- #include "Back-end.h"
- #include "Main.h"
-
- char *clipboard = NULL;
- int clipboard_size = 0;
-
- /* ----------------------------------------------------------------------- */
- /* Public functions */
-
- bool copy_to_clipboard(SF_SkyColours **sky, int start_band, int end_band)
- {
- wipe_clipboard();
-
- clipboard_size = (end_band - start_band) + 1;
- if(!flex_alloc((flex_ptr)&clipboard, clipboard_size))
- MG_RETV("NoMem", false); /* failed */
-
- for(int band = 0; band < clipboard_size; band++)
- clipboard[band] = get_shade(sky, (start_band + band));
-
- return true; /* success */
- }
-
- /* ----------------------------------------------------------------------- */
-
- char get_shade(SF_SkyColours **sky, int pos)
- {
- assert(pos >= 0 && pos <= 62);
- return ((*sky)->shade[1+(pos*2)] & 0xff); /* success */
- }
-
- /* ----------------------------------------------------------------------- */
-
- void write_shade(SF_SkyColours **sky, int pos, char mode13col)
- {
- /* Write shade to table with dithered transitions above and below */
- unsigned int mask1 = 0xff00ff00;
- unsigned int mask2 = 0x00ff00ff;
- unsigned int fullword = mode13col | (mode13col << 8) | (mode13col << 16) | (mode13col << 24);
-
- assert(pos >= 0 && pos <= 62);
-
- /* Set plain colour */
- (*sky)->shade[1+(pos*2)] = fullword;
-
- /* Dither with preceding colour */
- if(pos > 0) {
- (*sky)->shade[pos*2] = ((*sky)->shade[1 + ((pos-1)*2)] & mask1)
- | (fullword & mask2);
- }
- else
- (*sky)->shade[pos*2] = fullword;
-
- /* Dither with following colour */
- if(pos == 62)
- return;
- (*sky)->shade[(pos+1)*2] = ((*sky)->shade[1 + ((pos+1)*2)] & mask2)
- | (fullword & mask1);
- }
-
- /* ----------------------------------------------------------------------- */
-
- void smooth_section(SF_SkyColours **sky, int start_band, int end_band)
- {
- int last_trans, centre, last_centre;
- last_trans = start_band;
-
- for(int row = (start_band+1); row <= end_band; row++) {
-
- if(get_shade(sky, row) != get_shade(sky, last_trans)) { /* transition detected! */
-
- /* Check for first transition (e.g. where none prior */
- if(last_trans != start_band) {
- /* Calculate centrepoint of previous colour area */
- centre = last_trans + ((row - last_trans)/2);
-
- /* Re-paint transition between previous area and preceeding one */
- if((centre - last_centre) > 2)
- gradient_overwrite(sky, last_centre, centre, get_shade(sky, last_centre), get_shade(sky, centre), 3);
-
- /* init search for next transition / centre of new area */
- last_centre = centre;
- }
- else
- /* For first gradient, pretend that first row is prev centre */
- last_centre = start_band;
- last_trans = row;
- }
- }
- if(last_trans == start_band)
- return; /* not one transition!! */
-
- /* To smooth to last row, pretend that it is a final centre */
- if((end_band - last_centre) > 2)
- gradient_overwrite(sky, last_centre, end_band, get_shade(sky, last_centre), get_shade(sky, end_band), 3);
- }
-
- /* ----------------------------------------------------------------------- */
-
- void insert_from_clipboard(SF_SkyColours **sky, int start_band)
- {
- open_gap(sky, start_band, clipboard_size);
- for(int band = 0; band < clipboard_size && (start_band + band) < 63; band++)
- write_shade(sky, (start_band + band), clipboard[band]);
- }
-
- /* ----------------------------------------------------------------------- */
-
- void wipe_clipboard(void)
- {
- if(clipboard != NULL)
- flex_free((flex_ptr)&clipboard);
- clipboard = NULL;
- clipboard_size = 0;
- }
-
- /* ----------------------------------------------------------------------- */
-
- void open_gap(SF_SkyColours **sky, int start_band, int size)
- {
- /* Copy bands up to make room */
- for(int band = 62; band >= (start_band + size); band--)
- write_shade(sky, band, get_shade(sky, band-size));
- }
-
- /* ----------------------------------------------------------------------- */
-
- void remove_bands(SF_SkyColours **sky, int start_band, int end_band)
- {
- /* Copy bands down squashing offending ones */
- int size = (end_band - start_band) + 1;
- for(int band = start_band; band < 63; band++) {
- if(band + size < 63)
- write_shade(sky, band, get_shade(sky, band + size));
- else
- /* Black out newly exposed space at top */
- write_shade(sky, band, 0);
- }
- }
-
- /* ----------------------------------------------------------------------- */
-
- void plain_insert(SF_SkyColours **sky, int start_band, int size, char mode13col)
- {
- /* Insert new colour bands with specified shade */
- if(size < 1)
- return;
-
- open_gap(sky, start_band, size);
- plain_overwrite(sky, start_band, start_band+(size-1), mode13col);
- }
-
- /* ----------------------------------------------------------------------- */
-
- void plain_overwrite(SF_SkyColours **sky, int start_band, int end_band, char mode13col)
- {
- /* Change colour bands to specified shade */
- if(start_band < 0)
- start_band = 0;
- if(end_band > 62)
- end_band = 62;
-
- for(int band = start_band; band <= end_band; band++)
- write_shade(sky, band, mode13col);
- }
-
- /* ----------------------------------------------------------------------- */
-
- void gradient_insert(SF_SkyColours **sky, int start_band, int size, char start_col, char end_col, unsigned int end_flags)
- {
- /* Insert gradient fill between specified colours */
- if(size < 1)
- return;
- open_gap(sky, start_band, size);
- gradient_overwrite(sky, start_band, start_band+(size-1), start_col, end_col, end_flags);
- }
-
- /* ----------------------------------------------------------------------- */
-
- void gradient_overwrite(SF_SkyColours **sky, int start_band, int end_band, char start_col, char end_col, unsigned int end_flags)
- {
- /* Write gradient fill between specified colours
- end_flags b0 = include start colour
- b1 = include end colour */
-
- #ifndef NDEBUG
- {char string[256];
- sprintf(string, "report start col:%d target col:%d flags:%d", start_col, end_col, end_flags);
- _kernel_oscli(string);}
- #endif
-
- int dist = end_band - start_band;
- if(FLAG_SET(end_flags, 1u<<0)) {
- /* Include start colour */
- if(start_band >= 0 && start_band <= 62)
- write_shade(sky, start_band, start_col); /* write start shade */
- start_band++;
- } else
- dist++; /* an extra step (initial colour not drawn) */
-
- if(FLAG_SET(end_flags, 1u<<1)) {
- /* Include end colour */
- if(end_band >= 0 && end_band <= 62)
- write_shade(sky, end_band, end_col); /* write end shade */
- end_band--;
- } else
- dist++; /* an extra step (final colour not drawn) */
-
- if(dist <= 0)
- return; /* guard against division by zero */
-
- /* Get 24-bit palette entries for start/end colours */
- unsigned int first_paletteentry = palette[start_col];
- unsigned int last_paletteentry = palette[end_col];
-
- /* Calculate initial R/G/B values and increments for smooth gradient */
- float red_component = (float)((first_paletteentry & 0x0000ff00) >> 8);
- int red_diff = ((last_paletteentry & 0x0000ff00) >> 8) - (int)red_component;
- float red_inc = (float)red_diff/(float)dist;
- #ifndef NDEBUG
- {char string[256];
- sprintf(string, "report RED start=%f distance=%d increment=%f", red_component,red_diff,red_inc);
- _kernel_oscli(string);}
- #endif
-
- float green_component = (float)((first_paletteentry & 0x00ff0000) >> 16);
- int green_diff = ((last_paletteentry & 0x00ff0000) >> 16) - (int)green_component;
- float green_inc = (float)green_diff/(float)dist;
- #ifndef NDEBUG
- {char string[256];
- sprintf(string, "report GREEN start=%f distance=%d increment=%f", green_component,green_diff,green_inc);
- _kernel_oscli(string);}
- #endif
-
- float blue_component = (float)((first_paletteentry & 0xff000000) >> 24);
- int blue_diff = ((last_paletteentry & 0xff000000) >> 24) - (int)blue_component;
- float blue_inc = (float)blue_diff/(float)dist;
- #ifndef NDEBUG
- {char string[256];
- sprintf(string, "report BLUE start=%f distance=%d increment=%f", blue_component,blue_diff,blue_inc);
- _kernel_oscli(string);}
- #endif
-
- /* Write colour gradient... */
- for(int band = start_band; band <= end_band; band++) {
-
- /* Calculate transitional colour */
- red_component += red_inc;
- green_component += green_inc;
- blue_component += blue_inc;
- #ifndef NDEBUG
- {char string[256];
- sprintf(string, "report ideal colour for band %d is R=%f G=%f B=%f", band, red_component, green_component, blue_component);
- _kernel_oscli(string);
- char near = real_to_mode13col(((unsigned int)blue_component<<24) | ((unsigned int)green_component<<16) | ((unsigned int)red_component<<8));
- sprintf(string, "report nearest mode 13 colour:%d (R=%d G=%d B=%d)", near, (palette[near] & 0xff00)>>8, (palette[near] & 0xff0000)>>16, (palette[near] & 0xff000000)>>24);
- _kernel_oscli(string);}
- #endif
-
- /* Write nearest to ideal colour in default mode 13 palette */
- if(band >= 0 && band <= 62)
- write_shade(
- sky,
- band,
- real_to_mode13col(
- ((unsigned int)blue_component<<24) |
- ((unsigned int)green_component<<16) |
- ((unsigned int)red_component<<8)
- )
- );
- } /* next band */
- }
-